package cl.utalca.robot.logic;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

import cl.utalca.robot.dto.TestCaseDTO;
import cl.utalca.robot.dto.TestCaseResultDTO;
import cl.utalca.robot.dto.TestDTO;
import cl.utalca.robot.dto.TestResultDTO;


public class ExecuteRobot {

private static Scanner scanner;

public static void exec(TestDTO program){
		
		//Compilador comp = new Compilador();
		
		Runtime r = Runtime.getRuntime();
		try {
			
			Process process = r.exec(program.getLanguage().getCompileCommand() + program.getFilename());
			
			scanner = new Scanner(process.getInputStream());		
			
			
			while (scanner.hasNext()){
				
				System.out.println("SALIDA");
				System.out.println(scanner.next());
			}
			
			scanner = new Scanner(process.getErrorStream());			
			while (scanner.hasNext()){
					
				System.out.println("ERROR");
				System.out.println(scanner.next());
				
				process.destroy();
			}
			
			Process process2 = r.exec(program.getLanguage().getExecuteCommand() + program.getFilename());
			
			scanner = new Scanner(process2.getInputStream());
			while (scanner.hasNext()){
				
				System.out.println("SALIDA");
				System.out.println(scanner.next());
			}
			
			scanner = new Scanner(process2.getErrorStream());				
			while (scanner.hasNext()){
				
				System.out.println("ERROR");
				System.out.println(scanner.next());
			}
			
		}
		catch (IOException e) {
			e.printStackTrace();
		}
	}

	private static Boolean analizeCode(Runtime r, TestDTO p){
		
				
		Process process;
		try {
			process = r.exec(p.getLanguage().getCompileCommand() + " " + p.getFile().getPath());
		} catch (IOException e) {
			
			System.err.println("Error en generar el proceso");
			e.printStackTrace();
			return false;
		}
		
		scanner = new Scanner(process.getErrorStream());
		Boolean error = false;
		while (scanner.hasNext()){
				
			System.err.println(scanner.next());
			
			error = true;
		}		
		process.destroy();
		if(error)
			return false;
		else
			return true;
	}
		
	private static Map<Integer, TestCaseResultDTO> analizeTestCases(Runtime r, TestDTO p){
		
		TestCaseResultDTO result = null;
		
		Map<Integer, TestCaseResultDTO> testResults = new HashMap<>();
		
		int i = 0;
		for(TestCaseDTO testCase : p.getTestCasesList())
		{			
			result = runTestCase(testCase, r, p.getFile(), p);
			testResults.put(i, result);
			i++;
		}
		
		return testResults;
	}
	
	private static TestCaseResultDTO runTestCase(TestCaseDTO testCase, Runtime r, File file, TestDTO test) {
		
		Process process = null;
		String result = null;
		
		
			try {
				
				String path = preparePath(file, test);
				process = r.exec( path );
			} 
			catch (IOException e) {
				
				result = "Error en generar proceso";
			}
			scanner = new Scanner(process.getInputStream());
			
			String salida = "";
			
			while (scanner.hasNextLine()){
				
				salida += scanner.nextLine();
				System.out.println(salida);
				
			}

			int resultado = checkInputOutput(testCase.getOutput(), salida);
			
			switch (resultado) {
			case 1:
				
				result = "CODIGO CORRECTO";
				break;
			
			case 2:
				
				result = "ERROR DE FORMATO";
				break;
			default:
				
				result = "CODIGO ERRONEO";
				break;
			}
			
			scanner = new Scanner(process.getErrorStream());
			
			String error = "";
			while (scanner.hasNextLine()){

				error += scanner.nextLine();
			}			
			
			if(!error.isEmpty())
				System.out.println(error);
			
			process.destroy();
			
			TestCaseResultDTO testCaseResult = new TestCaseResultDTO();
			testCaseResult.setResult(result);
			testCaseResult.setRunningOutput(salida);
			testCaseResult.setTestCase(testCase);
			
			return testCaseResult;
	}

	private static String preparePath(File file, TestDTO test ) {
		
		String[] pathArray = file.getPath().split("\\\\");
		String pathWithoutName = "";
		
		for(int i = 0; i < pathArray.length-1; i++)
		{
			pathWithoutName += pathArray[i] + "\\";
		}
		pathWithoutName += " " + pathArray[pathArray.length-1].split("\\.")[0];
		
		
		String path = test.getLanguage().getExecuteCommand() + " " + pathWithoutName;
		
		return path;
	}

	private static int checkInputOutput(String testOutput, String realOutput){
		
		if(testOutput.equals(realOutput)){
			
			return 1;
		}
		else if(testOutput.equalsIgnoreCase(realOutput.trim())){
						
			return 2;
		}
		else 
			return 3;
	}
	
	public static TestResultDTO doTest(TestDTO p){
		
		TestResultDTO resp = new TestResultDTO();
		
		Runtime r = Runtime.getRuntime();
		
		resp.setHasCompilationError(analizeCode(r, p));		
		
		if(resp.getHasCompilationError())
			resp.setTestCasesResults(analizeTestCases(r, p));
		
		Boolean success = true;
		for (TestCaseResultDTO testCaseResult : resp.getTestCasesResults().values())
		{
			if(!testCaseResult.getResult().equals("CODIGO CORRECTO"))
			{
				success = false;
				break;
			}
		}
		
		resp.setSuccess(success);
		return resp;
	}
}
